<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | 注解实现中间件
// +----------------------------------------------------------------------
namespace Inphp\Core\Middlewares;

class Attribute implements IMiddleware
{
    /** 类 **/
    const TYPE_CLASS = "class";
    /** 属性 **/
    const TYPE_PROPERTY = "property";
    /** 方法 **/
    const TYPE_METHOD = "method";

    /**
     * 注解处理
     * @throws \ReflectionException
     */
    public static function process(...$args)
    {
        //
        list($notUse, $controller, $method) = $args;
        //如果控制器不存在，则无需处理
        if (!is_object($controller)) {
            return;
        }
        try {
            //类
            $ref = new \ReflectionClass($controller::class);
            $attrs = $ref->getAttributes();
            self::execute(self::TYPE_CLASS, $attrs, $controller);
            //类属性注解
            $properties = $ref->getProperties();
            foreach ($properties as $property) {
                $p_attrs = $property->getAttributes();
                self::execute(self::TYPE_PROPERTY, $p_attrs, $controller, $property->getName());
            }
            //方法注解
            $methods = $ref->getMethods();
            $methodNameList = [];
            foreach ($methods as $m) {
                $methodNameList[] = $m->name;
            }
            if (!empty($method) && in_array($method, $methodNameList)) {
                $m_ref = $ref->getMethod($method);
                $m_attrs = $m_ref->getAttributes();
                self::execute(self::TYPE_METHOD, $m_attrs, $controller, $method);
            }
        } catch (\ReflectionException $exception)
        {
            //抛出处理失败的异常
            throw new \ReflectionException("注解处理失败：".$exception->getMessage()."，{$exception->getFile()}第{$exception->getLine()}行", $exception->getCode());
        }
    }

    /**
     * 统一执行注解处理
     * @param string $type
     * @param array $attrs
     * @param mixed $controller
     * @param string|null $target
     */
    private static function execute(string $type, array $attrs, mixed &$controller, ?string $target = null)
    {
        foreach ($attrs as $attr) {
            $instance = $attr->getName();
            $args = $attr->getArguments();
            $init = new $instance(...$args);
            if (method_exists($init, 'process')) {
                $init->process($type, $controller, $target);
            }
        }
    }
}